home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / DBPCXL15.ARJ / SRC_C.ARJ / PCX.C next >
C/C++ Source or Header  |  1992-01-26  |  15KB  |  446 lines

  1. /* pcxlib.c  : A .PCX file decoder */
  2. #define  PCX_LIB
  3. #include <stdio.h>
  4. #include <io.h>
  5. #include <conio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <alloc.h>
  9. #include <mem.h>
  10. #include <dos.h>
  11. #include <errno.h>
  12.  
  13. #include "pcxlib.h"
  14.  
  15. char PCX16defpalette[16][3] = { { 0, 0, 0 },
  16.               { 0, 0, 0x80 }, { 0, 0x80, 0 },  { 0, 0x80, 0x80 },
  17.               { 0x80, 0, 0 }, { 0x80, 0, 0x80 }, { 0x80, 0x80, 0 },
  18.               { 0x80, 0x80, 0x80 }, { 0xc0, 0xc0, 0xc0 }, { 0, 0, 0xff },
  19.               { 0, 0xff, 0 }, { 0, 0xff, 0xff }, { 0xff, 0, 0 },
  20.               { 0xff, 0, 0xff }, { 0xff, 0xff, 0 }, { 0xff, 0xff, 0xff } };
  21.  
  22.  
  23. /****************************************************************************
  24. //     (PCXF *)fp=fopenPCXr("example.pcx");
  25. //
  26. //             returns NULL on error
  27. //             reads the header and palette into fp->h and fp->palette
  28. //             sets first mark [0] to the start of scan lines
  29. //             leaves ftell at the first scan line (line 0)
  30. //
  31. ****************************************************************************/
  32.  
  33. PCXF *  fopenPCXr (char *pathname)
  34. {
  35.     PCXF  *pcxfile;
  36.     int i;
  37.  
  38.     if (pcxdebug) {
  39.        fprintf(pcxdebug,"fopenPCXr(%s)\n", pathname);
  40.     }
  41.  
  42.     /* malloc memory for the PCXF, PCXH, and palette structures all at
  43.        once. */
  44.     if ( !(pcxfile=(PCXF *)
  45.           malloc( sizeof(PCXF) + sizeof(PCXH) + 768) ) ) {
  46.        PCXerror=ENOMEM; return(NULL);
  47.     }
  48.     pcxfile->h=NULL;
  49.     if ((pcxfile->fp=fopen(pathname, "rb")) == NULL) {
  50.        PCXerror=ENOPATH; fclosePCX(pcxfile); return(NULL);
  51.     }
  52.     pcxfile->read_or_write=0; /* readonly */
  53.     pcxfile->h=(PCXH *)((char *)pcxfile + sizeof(PCXF));
  54.     pcxfile->name=pathname;
  55.     /* read header from file */
  56.     if (fread(pcxfile->h,sizeof(PCXH),1,pcxfile->fp) != 1){
  57.         PCXerror=errno; fclosePCX(pcxfile); return (NULL);
  58.     }
  59.     if(pcxfile->h->MagicId != 0x0a) {
  60.         fclosePCX(pcxfile); PCXerror=EINVFMT; return (NULL);
  61.     }
  62.     pcxfile->w  = pcxfile->h->Xmax - pcxfile->h->Xmin + 1;
  63.     pcxfile->l = pcxfile->h->Ymax - pcxfile->h->Ymin + 1;
  64.     pcxfile->type=-1;
  65.  
  66.     /* set up marks : mark 0 is scan 16 */
  67.     pcxfile->num_marks=pcxfile->l/16;
  68.     pcxfile->marks=(long *)malloc( sizeof(long)*pcxfile->num_marks);
  69.     for (i=0; i<pcxfile->num_marks; i++) {
  70.         *(pcxfile->marks + i)=0L;
  71.     }
  72.  
  73.     /* Determine PCX file type */
  74.  
  75.     /* 256-color file */
  76.     if (pcxfile->h->BitsPixel == 8 && pcxfile->h->Planes == 1) {
  77.         pcxfile->type=PCX256colors;
  78.         pcxfile->h->bytesline = ALIGN_DWORD(pcxfile->h->bytesline);
  79.         pcxfile->image_size = (long) pcxfile->h->bytesline * pcxfile->l;
  80.         pcxfile->palette=(char *)((char *)pcxfile->h + sizeof(PCXH));
  81.         _read_palette(pcxfile);
  82.     } else
  83.     /* 16-color file */
  84.     if (pcxfile->h->BitsPixel == 1 && pcxfile->h->Planes == 4) {
  85.         pcxfile->h->bytesline = ALIGN_DWORD( (pcxfile->w+1)/2 );
  86.         pcxfile->image_size = pcxfile->h->bytesline * pcxfile->l;
  87.         pcxfile->type= PCX16colors;
  88.     } else
  89.     /* monochrome file */
  90.     if (pcxfile->h->BitsPixel == 1 && pcxfile->h->Planes == 1) {
  91.         pcxfile->type=PCXMONO;
  92.         pcxfile->h->bytesline = ALIGN_DWORD(pcxfile->h->bytesline);
  93.         pcxfile->image_size = pcxfile->h->bytesline * pcxfile->l;
  94.     }  else {
  95.         if (pcxdebug) fprintf(pcxdebug,"invfmt: unknown type.\n");
  96.         PCXerror=EINVFMT;
  97.     }
  98.     if ( (pcxfile->buffer=(unsigned char *)
  99.           malloc( pcxfile->h->bytesline * 16 ) ) == NULL){
  100.        PCXerror=ENOMEM; return(NULL);
  101.     }
  102.     pcxfile->next_scan=pcxfile->buffer_scan=-1;
  103.  
  104.     fseekPCX(pcxfile,0);
  105.     if (pcxdebug) {
  106.        fprintf(pcxdebug,
  107.                "p->h->bytesline=%u, p->l=%u, p->w=%u, p->type=%u\n",
  108.                pcxfile->h->bytesline, pcxfile->l, pcxfile->w, pcxfile->type);
  109.        fprintf(pcxdebug, "p=%Fp, p->h=%Fp, p->palette=%Fp\n",
  110.                          pcxfile, pcxfile->h, pcxfile->palette);
  111.     }
  112.     return ((!PCXerror) ? pcxfile : NULL);
  113. }
  114.  
  115. /*///////////////////////////////////////////////////////////////////////////
  116. //  (PCXF *)fp=fopenPCXw("example.pcx", (PCXH *)h, (char *)palette);
  117. //
  118. //             returns NULL on error
  119. //             opens the file in mode "wb" and writes the header,
  120. //             leaving ftell at the first scan line (end-of-file).
  121. //             _write_pcx_line() should be used sequentially to write the
  122. //             data into the file, followed by _write_pcx_palette(), then
  123. //             fclosePCX().
  124. ///////////////////////////////////////////////////////////////////////////*/
  125. PCXF  *   fopenPCXw(char *name, PCXH *h, char *palette)
  126. {
  127.     PCXF  *pcxfile;
  128.  
  129.     if (pcxdebug) {
  130.        fprintf(pcxdebug,"fopenPCXw(%s,%Fp,%Fp)\n", name,h,palette);
  131.     }
  132.  
  133.     /* malloc memory for the PCXF, PCXH, and palette structures all at
  134.        once. */
  135.     if ( !(pcxfile=(PCXF *)
  136.           malloc( sizeof(PCXF) + sizeof(PCXH) + 768 + h->bytesline) ) ) {
  137.        PCXerror=ENOMEM; return(NULL);
  138.     }
  139.     pcxfile->marks=NULL; pcxfile->num_marks=0; /* writing doesn't use marks */
  140.     pcxfile->palette=NULL;
  141.     if ((pcxfile->fp=fopen(name, "wb")) == NULL) {
  142.        PCXerror=ENOPATH; fclosePCX(pcxfile); return(NULL);
  143.     }
  144.     pcxfile->read_or_write=1; /* write only */
  145.     pcxfile->h=(PCXH *)((char *)pcxfile + sizeof(PCXF));
  146.     memcpy(pcxfile->h,h,sizeof(PCXH)); /* copy prepared header */
  147.     pcxfile->name=name;
  148.     /* write header to file */
  149.     if (fwrite(pcxfile->h,sizeof(PCXH),1,pcxfile->fp) != 1){
  150.         PCXerror=errno; fclosePCX(pcxfile); return (NULL);
  151.     }
  152.     pcxfile->w  = pcxfile->h->Xmax - pcxfile->h->Xmin + 1;
  153.     pcxfile->l = pcxfile->h->Ymax - pcxfile->h->Ymin + 1;
  154.     pcxfile->type=-1;
  155.  
  156.     /* Determine PCX file type */
  157.  
  158.     /* 256-color file */
  159.     if (pcxfile->h->BitsPixel == 8 && pcxfile->h->Planes == 1) {
  160.         pcxfile->type=PCX256colors;
  161.         pcxfile->h->bytesline = ALIGN_DWORD(pcxfile->h->bytesline);
  162.         pcxfile->image_size = (long) pcxfile->h->bytesline * pcxfile->l;
  163.         pcxfile->palette=(char *)((char *)pcxfile->h + sizeof(PCXH));
  164.         memcpy(pcxfile->palette,palette,768);
  165.                      /* copy prepared palette */
  166.         if (pcxdebug) {
  167.            fprintf(pcxdebug,"copied palette=%Fp to ->palette=%Fp.\n",
  168.                             palette, pcxfile->palette);
  169.            if ( memcmp(pcxfile->palette,palette,768) != 0)
  170.               fprintf(pcxdebug,"palette comparison failed.\n");
  171.         }
  172.     }  else
  173.     /* 16-color file */
  174.     if (pcxfile->h->BitsPixel == 1 && pcxfile->h->Planes == 4) {
  175.         pcxfile->h->bytesline = ALIGN_DWORD( (pcxfile->w+1)/2 );
  176.         pcxfile->image_size = pcxfile->h->bytesline * pcxfile->l;
  177.         pcxfile->type= PCX16colors;
  178.     }  else
  179.     /* monochrome file */
  180.     if (pcxfile->h->BitsPixel == 1 && pcxfile->h->Planes == 1) {
  181.         pcxfile->type=PCXMONO;
  182.         pcxfile->h->bytesline = ALIGN_DWORD(pcxfile->h->bytesline);
  183.         pcxfile->image_size = pcxfile->h->bytesline * pcxfile->l;
  184.     }  else
  185.         PCXerror=EINVFMT;
  186.     pcxfile->buffer=NULL; pcxfile->next_scan=pcxfile->buffer_scan=-1;
  187.  
  188.     fseekPCX(pcxfile,0);
  189.     if (pcxdebug) {
  190.        fprintf(pcxdebug,
  191.                "p->h->bytesline=%u, p->l=%u, p->w=%u, p->type=%u\n",
  192.                pcxfile->h->bytesline, pcxfile->l, pcxfile->w, pcxfile->type);
  193.        fprintf(pcxdebug, "p=%Fp, p->h=%Fp, p->palette=%Fp\n",
  194.                          pcxfile, pcxfile->h, pcxfile->palette);
  195.     }
  196.     return ((!PCXerror) ? pcxfile : NULL);
  197. }
  198.  
  199. /*///////////////////////////////////////////////////////////////////////////
  200. //  _read_pcx_line
  201. // returns number of characters written to linebuffer
  202. ///////////////////////////////////////////////////////////////////////////*/
  203. unsigned _read_pcx_line(PCXF *p, char * linebuffer,
  204.                                            unsigned x0, unsigned x1)
  205. {
  206.     unsigned int   n, w;
  207.     unsigned short run_len;
  208.     int Data;
  209.     /* n= file ptr, w=image ptr */
  210.     for (w=0,n=0; n < p->h->bytesline ; ) {
  211.         if ((Data=fgetc(p->fp)) == EOF) {
  212.             p->next_scan=-1;
  213.             return(n);
  214.         }
  215.         /* If the two high bits are set... */
  216.         if ((unsigned char)Data >= 0xc0) {
  217.             /* Get duplication count from lower bits */
  218.             run_len = (char)Data & 0x3f;
  219.             /* Set run_len bytes */
  220.             if ((Data=fgetc(p->fp)) == EOF)  {
  221.                p->next_scan=-1;
  222.                return(w);
  223.             }
  224.             while(run_len--) {
  225.                if ( ((n >= x0) && (n <= x1)) )
  226.                    linebuffer[w++]=(char)Data;
  227.                n++;
  228.             }
  229.         } else {
  230.             if ( ((n >= x0) && (n <= x1)) )
  231.                 linebuffer[w++]=(char)Data;
  232.             n++;
  233.         }
  234.     }
  235.     p->next_scan++;
  236.     return (w);
  237. }
  238.  
  239. /*///////////////////////////////////////////////////////////////////////////
  240. //  _write_pcx_line
  241. // returns number of characters written to linebuffer
  242. ///////////////////////////////////////////////////////////////////////////*/
  243. unsigned _write_pcx_line(PCXF *p, char * linebuffer,
  244.                             unsigned x0, unsigned x1, unsigned char fill)
  245. {
  246.     unsigned int   n=0, w=0;
  247.     unsigned char run_len, last, data;
  248.     /* n= linebuffer, w=image offsets */
  249.  
  250.     while (w < x0 ) {
  251.         if ( (x0 - w) > 63 )
  252.            run_len=63;
  253.         else
  254.            run_len=(x0-w);
  255.         if ( (run_len != 1) || (fill > 191) ) {
  256.            fputc( ( run_len | 0xc0 ),p->fp);
  257.         }
  258.         fputc(fill,p->fp);
  259.         w+=run_len;
  260.     }
  261.     run_len=1;
  262.     last=*(linebuffer+n); /* assign the first character */
  263.     w++;
  264.     for (n=1; (w < p->h->bytesline)&&(w <= x1); n++,w++) {
  265.         if ( (data=*(linebuffer+n)) == last) {
  266.            run_len++;
  267.            if ( run_len < 63 )
  268.               continue;
  269.         }
  270.         while (run_len) {
  271.            if ( (run_len != 1) || (last > 0xbf) ) {
  272.               fputc( (run_len | 0xc0),p->fp);
  273.            }
  274.            fputc(last,p->fp);
  275.            run_len=0;
  276.         }
  277.         last=data;
  278.         run_len=1;
  279.     }
  280.     /* left-overs */
  281.     while (run_len) {
  282.          if ( (run_len != 1) || (last > 0xbf) ) {
  283.             fputc( (run_len | 0xc0),p->fp);
  284.          }
  285.          fputc(last,p->fp);
  286.            run_len=0;
  287.     }
  288.  
  289.     while ( w < p->h->bytesline ) {
  290.         if ( (p->h->bytesline -1 -w) < 63)
  291.             run_len= (p->h->bytesline -1 -w);
  292.         else
  293.             run_len=63;
  294.         if ( (run_len != 1) || (fill > 191) )
  295.            fputc( (run_len | 0xc0),p->fp);
  296.         fputc(fill,p->fp);
  297.         w+=run_len;
  298.     }
  299.     p->next_scan++;
  300.     return (w);
  301. }
  302.  
  303. /*/////////////////////////////////////////////////////////////////////////
  304. //  int =fseekPCX(PCXF *pcxfile, unsigned y)
  305. //    -1 on error
  306. ///////////////////////////////////////////////////////////////////////////*/
  307. int  fseekPCX(PCXF *pcxfile, unsigned y)
  308. {
  309.     int i=0;
  310.     long lastm=128L;
  311.  
  312.     if (pcxdebug) {
  313.        fprintf(pcxdebug,"fseekPCX(%Fp, %u).\n", pcxfile, y);
  314.     }
  315.     if (y == pcxfile->next_scan) {
  316.        return(y);
  317.     }
  318.     if (y < 16) {   /* home */
  319.        if (fseek(pcxfile->fp, (long)sizeof(PCXH), SEEK_SET) != 0) {
  320.           pcxfile->next_scan=-1;
  321.           return(-1);
  322.        }
  323.        pcxfile->next_scan=0;
  324.        if (y==0)
  325.           return(0);
  326.     }
  327.     if ( y>15) {
  328.        if (pcxfile->num_marks > 0)  {
  329.           while ( (i<y) && (*(pcxfile->marks + (i/16-1)) != 0L) ) {
  330.                 lastm=*(pcxfile->marks + (i/16-1));
  331.                 i+=16;
  332.           }
  333.           if (i>15) i-=16;
  334.           if (fseek(pcxfile->fp, lastm, SEEK_SET) != 0) {
  335.              i=0;
  336.              if (fseek(pcxfile->fp, (long)sizeof(PCXH), SEEK_SET) != 0)
  337.                 return(-1);
  338.           }
  339.           pcxfile->next_scan=i;
  340.        }
  341.     }
  342.  
  343.     for (; i<y; i++) {
  344.        if ( ((i%16) == 0) && (i > 15)) {
  345.           *(pcxfile->marks + (i/16-1))=ftell(pcxfile->fp);
  346.        }
  347.        _read_pcx_line(pcxfile, NULL, 1, 0);
  348.     }
  349.     if ( ((i%16) == 0) && (i > 15))
  350.        *(pcxfile->marks + (i/16-1))=ftell(pcxfile->fp);
  351.     return(y);
  352. }
  353.  
  354. /****************************************************************************
  355. //    fclosePCX
  356. ****************************************************************************/
  357. int fclosePCX(PCXF *pcx)
  358. {
  359.    if (pcx->marks)     free(pcx->marks);
  360.    if (pcx->buffer)    free(pcx->buffer);
  361.    if (pcx->fp)        fclose(pcx->fp);
  362.    if (pcx)            free(pcx);
  363.    return(0);
  364. }
  365.  
  366. /*
  367. ///////////////////////////////////////////////////////////////////////////
  368. // Palette entries have values from 0 to ff.  Unfortunately, the VGA
  369. // BIOS only uses the least significant 6 bits (i.e. values 0 - 3f).
  370. // To adjust, right shift every entry by 2 bits ( divide by 4).
  371. ///////////////////////////////////////////////////////////////////////////
  372. */
  373. void  _read_palette(PCXF *p)
  374. {
  375.    int i;
  376.    char Id256Pal;
  377.    char *pal;
  378.  
  379.    /* Look for the palette at the end of the file */
  380.    if (fseek(p->fp, -769, SEEK_END) == -1) {
  381.      PCXerror=errno; return;
  382.    }
  383.    else {
  384.      /* It should start with a 0Ch byte */
  385.      if (!((fread(&Id256Pal,1,1,p->fp) == 1) && (Id256Pal == '\x0c'))) {
  386.        if (pcxdebug) fprintf(pcxdebug,"palette doesn't start with 0ch.\n");
  387.        PCXerror=EINVFMT; return;
  388.      }
  389.      else
  390.        if (fread(p->palette, 768, 1, p->fp) != 1) {
  391.          PCXerror=errno; return;
  392.        }
  393.        else {
  394.          pal=(char *)p->palette;
  395.          for (i=0; i<256; i++) {
  396.             *(pal+i*3) /=4; *(pal+i*3+1) /=4; *(pal+i*3+2) /=4;
  397.          }
  398.        }
  399.    }
  400.    return;
  401. }
  402.  
  403. void _write_pcx_palette(PCXF *p)
  404. {
  405.    char I256Pal=0x0c;
  406.    unsigned char *tp,*pp;
  407.    int i;
  408.  
  409.    if (fwrite(&I256Pal, 1, 1, p->fp) != 1)
  410.       PCXerror=errno;
  411.    else {
  412.       if ( (tp=(unsigned char *)malloc(768)) == NULL) {
  413.          PCXerror=ENOMEM;
  414.          return;
  415.       }
  416.       pp=p->palette;
  417.       for (i=0; i<256; i++) {
  418.           *(tp+i*3) = *(pp+i*3) * 4;
  419.           *(tp+i*3+1) = *(pp+i*3+1) *4;
  420.           *(tp+i*3+2) = *(pp+i*3+2) *4;
  421.       }
  422.       if (fwrite(tp, 768, 1, p->fp) != 1)
  423.          PCXerror=errno;
  424.    }
  425.    return;
  426. }
  427.  
  428. void Start_pcxdebug(char *path)
  429. {
  430.    if (debugtimeson)
  431.       pcxdebug=fopen(path,"a");
  432.    else
  433.       pcxdebug=fopen(path,"w");
  434.    debugtimeson++;
  435. }
  436.  
  437. void Close_pcxdebug(void)
  438. {
  439.    fclose(pcxdebug);
  440. }
  441.  
  442. int Puts_pcxdebug(char *string)
  443. {
  444.    return(fputs(string,pcxdebug));
  445. }
  446.